package com.tticar.invmanager.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.tticar.invmanager.common.Enum.CodeType;
import com.tticar.invmanager.common.Enum.PayBusinessType;
import com.tticar.invmanager.common.exception.MyServiceException;
import com.tticar.invmanager.common.shiro.MySecurityUtils;
import com.tticar.invmanager.common.utils.DateUtils;
import com.tticar.invmanager.common.utils.ServiceUtil;
import com.tticar.invmanager.common.utils.date.DateStyle;
import com.tticar.invmanager.common.utils.date.DateUtil;
import com.tticar.invmanager.entity.*;
import com.tticar.invmanager.entity.vo.*;
import com.tticar.invmanager.mapper.MSalesMapper;
import com.tticar.invmanager.service.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author joeyYan
 * @since 2018-08-13
 */
@Service
public class MSalesServiceImpl extends ServiceImpl<MSalesMapper, MSales> implements IMSalesService {

    @Autowired
    private ICodeCounterService codeCounterService;

    @Autowired
    private IMSalesService salesService;

    @Autowired
    private IMSalesDetailService salesDetailService;

    @Autowired
    private IOutRepositoryDetailService outRepositoryDetailService;

    @Autowired
    private IRepositoryCountService repositoryCountService;

    @Autowired
    private IPPayService payService;

    @Autowired
    private IPurchaseReturnService purchaseReturnService;


    @Override
    public Page selectPage(MSales mSales, MyPage<MSales> page) {
        Wrapper wrapper = new EntityWrapper();
        wrapper.orderBy("order_time", false);
        wrapper.like(Strings.isNotEmpty(mSales.getCode()), "code", mSales.getCode());
        wrapper.eq(mSales.getOrderStatus() != null, "order_status", mSales.getOrderStatus());
        wrapper.eq(mSales.getPayStatus() != null, mSales.PAY_STATUS, mSales.getPayStatus());
        wrapper.like(Strings.isNotEmpty(mSales.getCusName()), "cus_name", mSales.getCusName());
        wrapper.ge(mSales.getStartTime() != null, MSales.ORDER_TIME, mSales.getStartTime());
        wrapper.le(mSales.getEndTime() != null, MSales.ORDER_TIME, DateUtils.getInstance().getDateEndTime(mSales.getEndTime()));
        return this.selectMapsPage(page, wrapper);
    }

    @Override
    public Page buszStats(MSales mSales, MyPage<MSales> page) {
        Wrapper wrapper = new EntityWrapper();
        wrapper.orderBy("order_time", false);
        wrapper.eq(mSales.getOrderStatus() != null, "order_status", mSales.getOrderStatus());
        wrapper.ge(mSales.getStartTime() != null, MSales.ORDER_TIME, mSales.getStartTime());
        wrapper.le(mSales.getEndTime() != null, MSales.ORDER_TIME, DateUtils.getInstance().getDateEndTime(mSales.getEndTime()));
        wrapper.eq(StringUtils.isNotEmpty(mSales.getUsername()), "username", mSales.getUsername());
        return this.selectMapsPage(page, wrapper);
    }

    @Override
    public Map getSumInfo(MSales mSales) {
        Wrapper wrapper = new EntityWrapper();
        wrapper.eq(mSales.getOrderStatus() != null, "order_status", mSales.getOrderStatus());
        wrapper.eq(StringUtils.isNotEmpty(mSales.getUsername()), "username", mSales.getUsername());
        wrapper.ge(mSales.getStartTime() != null, MSales.ORDER_TIME, mSales.getStartTime());
        wrapper.le(mSales.getEndTime() != null, MSales.ORDER_TIME, DateUtils.getInstance().getDateEndTime(mSales.getEndTime()));
        List<MSales> list = this.selectList(wrapper);

        BigDecimal totalFee = BigDecimal.ZERO;
        Integer totalNum = 0;
        for(MSales sales : list) {
            totalFee = totalFee.add(sales.getTotalFee());
//            totalNum += sales.getTotalNum();
        }
        totalNum = list.size();
        Map<String, Object> result = new HashMap<>();
        result.put("totalFee",totalFee);
        result.put("totalNum", totalNum);
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<Long> ids) {
        List list = new ArrayList();
        for (Long id : ids) {
            MSales mSales = new MSales();
            mSales.setId(id);
            //删除为-1，区分删除和禁用
            mSales.setStatus(-1);
            list.add(mSales);
        }
        this.updateBatchById(list);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addSales(SalesAddDto dto) throws ParseException {
        Date now = new Date();
//        Integer payStatus = dto.getPayingFee().compareTo(BigDecimal.ZERO) == 0 ? 1 : 0;
        Integer orderStatus = dto.getType() == 0 ? 0 : 1;

        //销售主表
        MSales sales = new MSales();
        sales.setCode(codeCounterService.getOrderCode(CodeType.XS));
        sales.setOrderType(0);
        sales.setOrderStatus(orderStatus);
        sales.setPayStatus(0);
        sales.setCusId(dto.getCusId());
//        sales.setCusName(dto.getCusName());
//        sales.setCusTel(dto.getCusTel());
//        sales.setCusAddr(dto.getCusAddr());
        sales.setTotalNum(dto.getTotalNum());
//        sales.setGoodsFee(dto.getTotalFee());
        sales.setTotalFee(dto.getTotalFee());
//        sales.setDiscountFee(dto.getDiscountFee());
//        sales.setPayedFee(dto.getPayedFee());
//        sales.setPayingFee(dto.getPayingFee());
//        sales.setLogisticsName(dto.getLogisticsName());
//        sales.setLogisticsNo(dto.getLogisticsNo());
//        sales.setDistributeName(dto.getDistributeName());
//        sales.setDistributeTel(dto.getDistributeTel());
        sales.setOrderTime(DateUtil.StringToDate(dto.getOrderTime(), DateStyle.YYYY_MM_DD));
        sales.setUsername(MySecurityUtils.currentUser().getUsername());
        sales.setCtime(now);
        if (dto.getType() == 0) {
            sales.setPayingFee(dto.getRealPay());
        } else {
            if (dto.getRealPay().compareTo(dto.getTotalFee()) > -1) {
                sales.setOrderStatus(1);
            }
            dto.setPayedFee(dto.getRealPay());
        }
        sales.setRemark(dto.getRemark());
        sales.setSettlementStatus(dto.getPayStatus());
        sales.setOrderType(dto.getOrderType());
        this.insert(sales);

        String ckCode = codeCounterService.getOrderCode(CodeType.CK);
        for(SalesGoodsDto tmp : dto.getGoodsList()) {
            MSalesDetail detail = new MSalesDetail();
            detail.setSalesId(sales.getId());
            detail.setBatchCode(tmp.getHouse());
            detail.setPrice(tmp.getAmountActual());
            detail.setNum(tmp.getCount());
            detail.setFee(tmp.getShouldPay());
            detail.setRemark(tmp.getRemark());
            detail.setSkuId(tmp.getSkuId());
            this.salesDetailService.insert(detail);

            if (orderStatus == 1 || orderStatus == 2) {//已发货，已完成时需要出库
                //去除库位批次后的出库
                Integer count = tmp.getCount();
                List<RepositoryCount> repositoryCounts = repositoryCountService.queryOutRepository(tmp.getSkuId());
                if (repositoryCounts != null && repositoryCounts.size() > 0) {
                    for (RepositoryCount rep : repositoryCounts) {


                            Long wearhouseId = rep.getWearhouseId();

                            Integer num = Integer.valueOf(rep.getCount() > count?count:rep.getCount());

                            OutRepositoryDetail outDetail = new OutRepositoryDetail();
                            outDetail.setSkuId(detail.getSkuId());
                            outDetail.setCode(ckCode);
                            outDetail.setBuszId(detail.getId());
                            outDetail.setWearhouseId(wearhouseId);
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                            outDetail.setOrderTime(sdf.parse(dto.getOrderTime()));
                            outDetail.setType(0);
                            outDetail.setCount(num);
                            outDetail.setStatus(0);
                            outDetail.setCtime(now);
                            outDetail.setUsername(MySecurityUtils.currentUser().getUsername());
                            outDetail.setRemark(sales.getRemark());
                            outDetail.setProviderId(sales.getCusId());
                            outRepositoryDetailService.insertOrUpdate(outDetail);

                            repositoryCountService.updateRepositoryCount(detail.getSkuId(), wearhouseId, num * -1);

                            count = count - rep.getCount();
                        if (count <= 0) {
                            break;
                        }

                    }
                } else {
                    throw new MyServiceException("货物库存不足");
                }


            }
        }

        //支付
//        if(dto.getPayedFee().compareTo(BigDecimal.ZERO) != 0) {
//            PPay pay = new PPay();
//            pay.setBusinessId(sales.getId());
//            pay.setBusinessType(1);
//            pay.setType(dto.getPayType());
//            pay.setAmount(dto.getPayFee());
//            pay.setRemainAmount(sales.getPayingFee());
//            pay.setFeeNote("销售支付");
//            pay.setRemark(dto.getPayRemark());
//            pay.setFeeType(1);
//            pay.setUseType(1);
//            pay.setStatus(0);
//            pay.setCtime(now);
//            pay.setUsername(MySecurityUtils.currentUser().getUsername());
//            this.payService.insert(pay);
//        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String outRepo(SalesAddDto dto) throws ParseException {
        String ckCode = codeCounterService.getOrderCode(CodeType.CK);
        Date now = new Date();
        List<OutRepositoryDetail> outList = new ArrayList<>();
        for(SalesGoodsDto tmp : dto.getGoodsList()) {

            List<RepositoryCount> repositoryCounts = repositoryCountService.queryOutRepository(tmp.getSkuId());
            if (repositoryCounts != null && repositoryCounts.size() > 0) {
                Integer totalNum = 0;
                Integer count = tmp.getCount();
                for (RepositoryCount rep : repositoryCounts) {
                    Integer num = Integer.valueOf(rep.getCount() > count?count:rep.getCount());
                    totalNum += num;
                    OutRepositoryDetail outDetail = new OutRepositoryDetail();
                    outDetail.setSkuId(tmp.getSkuId());
                    outDetail.setCode(ckCode);
                    outDetail.setBuszId(tmp.getId());
                    outDetail.setWearhouseId(rep.getWearhouseId());
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    outDetail.setOrderTime(sdf.parse(dto.getOrderTime()));
                    outDetail.setType(0);
                    outDetail.setCount(num);
                    outDetail.setRemark(tmp.getRemark());
                    outDetail.setStatus(0);
                    outDetail.setCtime(now);
                    outDetail.setUsername(MySecurityUtils.currentUser().getUsername());
                    if (outDetail.getCount() > 0) {
                        outList.add(outDetail);
                    }
                    if (totalNum >= count) {
                        break;
                    }
                }
            }


//            index++;
//            String house = tmp.getHouse();
//            String[] arr = house.split(",");
//            for(int i=0; i<arr.length; i++) {
//                String[] arr2 = arr[i].split("_");
//                Long wearhouseId = Long.valueOf(arr2[0]);
//                Long positionId = Long.valueOf(arr2[2]);
//                String batchCode = arr2[4];
//                Integer num = Integer.valueOf(arr2[6]);
//
//                //判断当前批次数量是否足够
//                Long curNum = this.inRepositoryDetailService.getSkuNumByBatchCode(tmp.getSkuId(), batchCode);
//                if(curNum.intValue() < num) {
//                    return "第" + index + "行批次需重新分配";
//                }
//
//                OutRepositoryDetail outDetail = new OutRepositoryDetail();
//                outDetail.setSkuId(tmp.getSkuId());
//                outDetail.setCode(ckCode);
//                outDetail.setBuszId(tmp.getId());
//                outDetail.setBatchNumber(batchCode);
//                outDetail.setWearhouseId(wearhouseId);
//                outDetail.setPositionId(positionId);
//                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//                outDetail.setOrderTime(sdf.parse(dto.getOrderTime()));
//                outDetail.setType(0);
//                outDetail.setCount(num);
//                outDetail.setRemark(tmp.getRemark());
//                outDetail.setStatus(0);
//                outDetail.setCtime(now);
//                outDetail.setUsername(MySecurityUtils.currentUser().getUsername());
//
//                outList.add(outDetail);
//            }
        }
        for(OutRepositoryDetail outDetail : outList) {
            outRepositoryDetailService.insertOrUpdate(outDetail);

            repositoryCountService.updateRepositoryCount(outDetail.getSkuId(), outDetail.getWearhouseId(),outDetail.getCount() * -1);
        }

//        for(OutRepositoryDetail outDetail : outList) {
//            outRepositoryDetailService.insertOrUpdate(outDetail);
//
//            repositoryCountService.updateRepositoryCountByPositionId(outDetail.getSkuId(), outDetail.getWearhouseId(), outDetail.getPositionId(), outDetail.getCount() * -1);
//        }

        MSales sales = this.salesService.selectById(dto.getSalesId());
        if(sales.getPayingFee() != null && sales.getPayingFee().compareTo(BigDecimal.ZERO) > 0) {
            sales.setOrderStatus(1);
        } else {
            sales.setOrderStatus(2);
        }
        this.salesService.updateById(sales);

        return "success";
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pay(Long salesId, BigDecimal payFee, Integer payType, String payRemark) {
        MSales sales = this.selectById(salesId);
        PPay pay = new PPay();
        pay.setBusinessType(PayBusinessType.SALE.getCode());
        pay.setBusinessId(salesId);
        pay.setType(payType);
        pay.setAmount(payFee);
        pay.setRemainAmount(sales.getPayingFee().subtract(payFee));
        pay.setFeeNote("销售支付");
        pay.setRemark(payRemark);
        pay.setFeeType(1);
        pay.setUseType(1);
        pay.setStatus(0);
        pay.setUsername(ServiceUtil.getLoginUserName());
        this.payService.insert(pay);

        sales.setPayedFee(sales.getPayedFee().add(payFee));
        sales.setPayingFee(sales.getPayingFee().subtract(payFee));
        if(sales.getPayingFee().compareTo(BigDecimal.ZERO) == 0) {
            sales.setPayStatus(1);
            if(sales.getOrderStatus() == 1) {
                sales.setOrderStatus(2);
            }
        }
        this.updateById(sales);
    }

    @Override
    public Page search(SalesSearchDto searchDto, MyPage<MSales> page) {
        return page.setRecords(this.baseMapper.search(searchDto, page));
    }

    @Override
    public List<Map> getSaleDetailList(Long saleId) {
        return this.baseMapper.getSaleDetailList(saleId);
    }

    @Override
    @Transactional
    public void outRepositoryFromWindow(Long saleId, List<PurchaseGoodsDto> goodsDtoList, BigDecimal realPay, BigDecimal totalMoney, Integer payStatus, String remark) {
        Wrapper wrapper = new EntityWrapper<>();
        wrapper.eq("sales_id", saleId);
        List<MSalesDetail> mSalesDetails = salesDetailService.selectList(wrapper);
        Wrapper wrapper1 = new EntityWrapper<>();
        wrapper1.eq("id", saleId);
        MSales mSales = selectOne(wrapper1);
        mSales.setOrderStatus(1);
        mSales.setGoodsFee(totalMoney);

        //销售出库结算
        mSales.setPayedFee(realPay);
        mSales.setPayStatus(payStatus);
        if (realPay != null && realPay.compareTo(totalMoney) > -1) {
            mSales.setPayStatus(1);
        }
        mSales.setRemark(remark);
        this.updateById(mSales);

        Date outDate = new Date();
        outDate.setHours(0);
        outDate.setMinutes(0);
        outDate.setSeconds(0);
        String ckCode = codeCounterService.getOrderCode(CodeType.CK);
        for (MSalesDetail dtoFromDB : mSalesDetails) {
            for (PurchaseGoodsDto dtoFromPage : goodsDtoList) {
                if (dtoFromPage.getSkusId().equals(dtoFromDB.getSkuId())) {
                    dtoFromDB.setPrice(new BigDecimal(dtoFromPage.getAmountActual()));
                    dtoFromDB.setNum(dtoFromPage.getCount());
                    salesDetailService.updateById(dtoFromDB);
                    List<RepositoryCount> repositoryCounts = repositoryCountService.queryOutRepository(dtoFromPage.getSkusId());
                    Integer count = dtoFromPage.getCount();
                    Integer totalCount = 0;
                    if (repositoryCounts != null && repositoryCounts.size() > 0) {
                        for (RepositoryCount rep : repositoryCounts) {
                            Long wearhouseId = rep.getWearhouseId();
                            Integer num = rep.getCount() > count ? count : rep.getCount();
                            OutRepositoryDetail outRepositoryDetail = new OutRepositoryDetail();
                            outRepositoryDetail.setSkuId(dtoFromPage.getSkusId());
                            outRepositoryDetail.setCount(num);
                            outRepositoryDetail.setType(0);
                            outRepositoryDetail.setUsername(MySecurityUtils.currentUser().getUsername());
                            outRepositoryDetail.setWearhouseId(wearhouseId);
                            outRepositoryDetail.setCode(ckCode);
                            outRepositoryDetail.setBuszId(dtoFromDB.getId());
                            outRepositoryDetail.setOrderTime(outDate);
                            outRepositoryDetail.setRemark(mSales.getRemark());
                            outRepositoryDetail.setProviderId(mSales.getCusId());
                            outRepositoryDetailService.insert(outRepositoryDetail);
                            repositoryCountService.updateRepositoryCount(outRepositoryDetail.getSkuId(), outRepositoryDetail.getWearhouseId(), outRepositoryDetail.getCount() * -1);
                            count = count - rep.getCount();
                            totalCount += num;
                            if (count <= 0) {
                                break;
                            }

                        }
                    } else {
                        throw new MyServiceException("库存不足，无法出库");
                    }
                    if (totalCount < dtoFromPage.getCount()) {
                        throw new MyServiceException("库存不足，无法出库");
                    }
                }
            }
        }

    }

    @Override
    public void endCountSale(Long saleId, BigDecimal realPay,BigDecimal totalMoney, Integer payStatus, String remark) {
        MSales mSales = this.selectById(saleId);
        mSales.setPayStatus(1);
//        if (realPay.compareTo(totalMoney) >= 0) {
//            mSales.setPayStatus(1);
//        }
        mSales.setPayedFee(totalMoney);
//        mSales.setRemark(remark);
        this.updateById(mSales);
    }

    /**
     * 撤销出库
     * */
    @Override
    public void cancelOutSale(Long saleId) {
        Wrapper wrapper = new EntityWrapper<>();
        wrapper.eq("id", saleId);
        MSales mSales = this.selectOne(wrapper);
        mSales.setOrderStatus(0);

        mSales.setPayStatus(0);
        mSales.setPayedFee(BigDecimal.ZERO);
        this.updateById(mSales);

        Wrapper<MSalesDetail> wrapperDetail = new EntityWrapper<>();
        wrapperDetail.eq("sales_id", saleId);
        List<MSalesDetail> mSalesDetails = salesDetailService.selectList(wrapperDetail);
        List idList = new ArrayList<>();
        for (MSalesDetail detail : mSalesDetails) {
            idList.add(detail.getId());
        }

        Wrapper outRepWrapper = new EntityWrapper<>();
        outRepWrapper.eq("type", 0);
        outRepWrapper.in("busz_id", idList);
        outRepWrapper.eq("status", 0);
        List<OutRepositoryDetail> outRepositoryDetails = outRepositoryDetailService.selectList(outRepWrapper);
        for (OutRepositoryDetail out : outRepositoryDetails) {
            out.setStatus(-1);
            repositoryCountService.updateRepositoryCount(out.getSkuId(),out.getWearhouseId(),out.getCount());
        }
        outRepositoryDetailService.updateBatchById(outRepositoryDetails);
    }

    @Override
    public void cancelSaleEnd(Long saleId) {
        Wrapper wrapper = new EntityWrapper<>();
        wrapper.eq("id", saleId);
        MSales mSales = this.selectOne(wrapper);
        mSales.setPayStatus(0);
        mSales.setPayedFee(BigDecimal.ZERO);
        this.updateById(mSales);
    }

    /**
     * 结算应收款单
     * */
    @Override
    public void endCountForInCome(List<String> codes) {
        for (String code : codes) {
            if (code.contains("XS")) {
                Wrapper wrapper = new EntityWrapper<>();
                wrapper.eq("code", code);
                MSales mSales = this.selectOne(wrapper);
                mSales.setPayStatus(1);
                mSales.setPayedFee(mSales.getTotalFee());
                this.updateById(mSales);
            } else if (code.contains("CT")) {
                Wrapper wrapper = new EntityWrapper<>();
                wrapper.eq("code", code);
                List<PurchaseReturn> purchaseReturns = purchaseReturnService.selectList(wrapper);
                BigDecimal totalMoney = BigDecimal.ZERO;
                for (PurchaseReturn entity : purchaseReturns) {
                    totalMoney = totalMoney.add(entity.getUnitPrice().multiply(new BigDecimal(entity.getCount())));
                }
                for (PurchaseReturn entity : purchaseReturns) {
                    entity.setPayStatus(1);
                    entity.setRealPay(totalMoney);
                }
                purchaseReturnService.updateBatchById(purchaseReturns);
            }
        }
    }




}
